#include <msclr/marshal_cppstd.h>
#include "DemoContext.h"
#include "../engine/SWRenderer.h"
#include "../engine/MeshModel.h"

using System::EventArgs;
using System::Windows::Forms::Keys;
using msclr::interop::marshal_as;

void DemoContext::OnInitialized()
{
	_data = new DemoContexData();
	_data->renderer = RendererPtr(new SWRenderer());
	_data->scene = ScenePtr(new Scene());
	
	Initialized(this, EventArgs::Empty);
}

DemoContext::~DemoContext()
{
	delete _data;
}

void DemoContext::Draw()
{
	if (_data != nullptr) {
		_data->renderer->startScene();
		_data->scene->render(_data->renderer);
		_data->renderer->endScene();

		::SwapBuffers(_device);
	}
}

void DemoContext::UpdateSize()
{
	if (_data != nullptr) {
		_data->renderer->resize();
	}
}

CvarWrapper^ DemoContext::GetCvar(String^ name)
{
	return GetCvar(name, false);
}

CvarWrapper^ DemoContext::GetCvar(String^ name, bool createIfNotExists)
{
	CvarSystem& cvars = CvarSystem::getInstance();
	CvarPtr cvar = cvars.getCvar(marshal_as<string>(name), createIfNotExists);
	return gcnew CvarWrapper(cvar.get());
}

CvarWrapper^ DemoContext::CreateCvar(String^ name, int defaultValue)
{
	CvarSystem& cvars = CvarSystem::getInstance();
	CvarPtr cvar = cvars.addCvar(marshal_as<string>(name), defaultValue);
	return gcnew CvarWrapper(cvar.get());
}

CvarWrapper^ DemoContext::CreateCvar(String^ name, bool defaultValue)
{
	CvarSystem& cvars = CvarSystem::getInstance();
	CvarPtr cvar = cvars.addCvar(marshal_as<string>(name), defaultValue);
	return gcnew CvarWrapper(cvar.get());
}

CvarWrapper^ DemoContext::CreateCvar(String^ name, float defaultValue)
{
	CvarSystem& cvars = CvarSystem::getInstance();
	CvarPtr cvar = cvars.addCvar(marshal_as<string>(name), defaultValue);
	return gcnew CvarWrapper(cvar.get());
}

void DemoContext::LoadCamera(
	float eye_x, float eye_y, float eye_z,
	float at_x, float at_y, float at_z,
	float up_x, float up_y, float up_z)
{
	CameraPtr camera(new Camera(
		Vec3(eye_x, eye_y, eye_z),
		Vec3(at_x, at_y, at_z),
		Vec3(up_z, up_y, up_z)
	));

	_data->scene->addCamera(camera);
}

void DemoContext::LoadMeshModel(String^ file)
{
	ModelPtr model(new MeshModel(marshal_as<string>(file)));
	_data->scene->addModel(model);
}

CameraWrapper^ DemoContext::GetActiveCamera()
{
	CameraPtr camera = _data->scene->getActiveCamera();
	if (camera.hasValue())
		return gcnew CameraWrapper(camera.get());
	else
		return nullptr;
}

ModelWrapper^ DemoContext::GetActiveModel()
{
	ModelPtr model = _data->scene->getActiveModel();
	if (model.hasValue())
		return gcnew ModelWrapper(model.get());
	else
		return nullptr;
}

bool DemoContext::IsInputKey(Keys keyData)
{
	switch (keyData)
	{
	case Keys::Right:
	case Keys::Left:
	case Keys::Up:
	case Keys::Down:
	case Keys::Shift | Keys::Right:
	case Keys::Shift | Keys::Left:
	case Keys::Shift | Keys::Up:
	case Keys::Shift | Keys::Down:
		return true;
	}

	return Control::IsInputKey(keyData);
}	
